// Controller.m
// By Jayson Adams, NeXT Developer Support Team
// You may freely copy, distribute and reuse the code in this example.
// NeXT disclaims any warranty of any kind, expressed or implied, as to its
// fitness for any particular use.

#import <appkit/appkit.h>
#import <objc/NXStringTable.h>

#import "Controller.h"
#import "CustomCell.h"
#import "NiftyMatrix.h"
#import "PostScriptView.h"

@implementation Controller:Object


/* delegation methods */

- appDidInit:sender
{
  /* create a matrix and stick it in the scroll view */
    [self createScrollingMatrix];
    
  /* bring the window on screen */
    [[scrollView window] makeKeyAndOrderFront:NULL];

    [self setupTileView];
    [[tileScrollView window] orderFront:NULL];
    
    return self;
}

/* instance methods */

- createScrollingMatrix
{
    NXRect	scrollRect, matrixRect;
    NXSize	interCellSpacing = {0.0, 0.0}, cellSize;
    
  /* set the scrollView's attributes */
    [scrollView setBorderType:NX_BEZEL];
    [scrollView setVertScrollerRequired:YES];
    [scrollView setHorizScrollerRequired:NO];
		
  /* get the scrollView's dimensions */
    [scrollView getFrame:&scrollRect];

  /* determine the matrix bounds */
    [ScrollView getContentSize:&(matrixRect.size)
    		forFrameSize:&(scrollRect.size)
		horizScroller:YES
		vertScroller:YES
		borderType:NX_BEZEL];
    
  /* prepare a matrix to go inside our scrollView */
    matrix = [[NiftyMatrix alloc] initFrame:&matrixRect 
				  mode:NX_LISTMODE
				  cellClass:[CustomCell class]
				  numRows:0
				  numCols:1];
    
  /* we don't want any space between the matrix's cells  */
    [matrix setIntercell:&interCellSpacing];
      
  /* fill the matrix with some cells */
    [self fillMatrix];
    
  /* resize the matrix's cells and size the matrix to contain them */
    [matrix getCellSize:&cellSize];
    cellSize.width = NX_WIDTH(&matrixRect);
    [matrix setCellSize:&cellSize];
    [matrix sizeToCells];
    [matrix setAutosizeCells:YES];
    
  /*
   * when the user clicks in the matrix and then drags the mouse out of
   * scrollView's contentView, we want the matrix to scroll
   */
    [matrix setAutoscroll:YES];
    
  /* stick the matrix in our scrollView */
    [scrollView setDocView:matrix];
    
  /* set things up so that the matrix will resize properly */
    [[matrix superview] setAutoresizeSubviews:YES];
    [matrix setAutosizing:NX_WIDTHSIZABLE];
    
  /* set the matrix's single- and double-click actions */
    [matrix setTarget:self];
    [matrix setAction:@selector(singleClick:)];
    [matrix setDoubleAction:@selector(doubleClick:)];
    
  /* select a cell, for starters */
    [[matrix selectCellAt:0 :0] sendAction];
    
    return self;
}

- fillMatrix
{
    BOOL	done = NO;
    char	buffer[10];
    int		i = 0;
    const char	*string;
    id		newCell;
    
  /* create a cell for each string */
    while (!done) {
	sprintf(buffer, "%d", i);
	if (string = [stringTable valueForStringKey:buffer]) {
          /* create a new cell if there's a string */
	    [matrix addRow];
	    newCell = [matrix cellAt:i :0];
	    [newCell setTag:(i * 16)];
	    [newCell setStringValueNoCopy:string];
	} else {
	    done = YES;
	}
	i++;
    }
    
  return self;
}

- setupTileView
{
    const NXRect	*paperRect;
    NXCoord		leftMargin, rightMargin, topMargin, bottomMargin;
    NXRect		psViewRect;

    [tileScrollView setVertScrollerRequired:YES];
    [tileScrollView setHorizScrollerRequired:YES];
    [tileScrollView setBorderType:NX_NOBORDER];

  /* get the paper's bounds (8.5 x 11) and margins */
    paperRect = [[NXApp printInfo] paperRect];
    [[NXApp printInfo] getMarginLeft:&leftMargin
    		       right:&rightMargin
		       top:&topMargin
		       bottom:&bottomMargin];
    
  /* the docView should fit within the margins */      
    psViewRect = *paperRect;
    psViewRect.size.width -= (leftMargin + rightMargin);
    psViewRect.size.height -= (topMargin + bottomMargin);
    
  /* create the docView and place it within its scrollView */
    psView = [[PostScriptView alloc] initFrame:&psViewRect];
    [tileScrollView setDocView:psView];

    return self;
}

- nextItem:sender
{
    int		nextRow;
    
  /* don't move to the "next" cell if multiple cells selected */
    if ([self multipleCellsSelected]) {
	NXRunAlertPanel(NULL,
			[stringTable valueForStringKey:"mulCellsSelected"],
			[stringTable valueForStringKey:"oops"], NULL, NULL);
	return self;
    }
    
  /* can't select the next cell if there isn't a currently-selected cell */
    if (![matrix selectedCell]) {
	NXRunAlertPanel(NULL,
			[stringTable valueForStringKey:"noCurrentCell"],
			[stringTable valueForStringKey:"yikes"], NULL, NULL);
	return self;
    }
    
  /* select the next cell, if it exists */
    nextRow = [matrix selectedRow] + 1;
    if (nextRow != [matrix cellCount]) {
	[matrix selectCellAt:nextRow :0];
      
      /* make sure it's visible */
	[matrix scrollCellToVisible:nextRow :0];
      
      /* behave as if the user clicked on the newly-selected cell */
	[matrix sendAction];
    } else {
	NXRunAlertPanel(NULL,
			[stringTable valueForStringKey:"nextCellNonexistant"],
			[stringTable valueForStringKey:"bummer"], NULL, NULL);
    }
    
    return self;
}

- previousItem:sender
{
    int		previousRow;
    
  /* don't move to the "previous" cell if multiple cells selected */
    if ([self multipleCellsSelected]) {
	NXRunAlertPanel(NULL,
			[stringTable valueForStringKey:"mulCellsSelected"],
			[stringTable valueForStringKey:"oops"], NULL, NULL);
	return self;
    }
    
  /* can't select previous cell if there no currently-selected cell */
    if (![matrix selectedCell]) {
	NXRunAlertPanel(NULL,
			[stringTable valueForStringKey:"noCurrentCell"],
			[stringTable valueForStringKey:"yikes"], NULL, NULL);
	return self;
    }
    
  /* select the previous cell, if it exists */
    previousRow = [matrix selectedRow] - 1;
    if (previousRow != -1) {
	[matrix selectCellAt:previousRow :0];
      
      /* make sure the newly-selected cell's visible */
	[matrix scrollCellToVisible:previousRow :0];
      
      /* behave as if the user clicked on the newly-selected cell */
	[matrix sendAction];
    } else {
	NXRunAlertPanel(NULL,
			[stringTable valueForStringKey:"prevCellNonexistant"],
			[stringTable valueForStringKey:"bummer"], NULL, NULL);
    }
    
    return self;
}

- (BOOL)multipleCellsSelected
{
  /* reset the counter */
    selectedCount = 0;
    
  /* get each selected cell to send the incrementCount method to us */
    [matrix sendAction:@selector(incrementCount:) to:self forAllCells:NO];
    
  /* if more than one, return true */
    return (selectedCount > 1);
}

- (BOOL)incrementCount:sender
{
  /*
   * once the counter reaches two, we know that more than one cell's
   * selected;  if that's the case, return NO so that the matrix will
   * discontinue having selected cells send incrementCount: to us
   */
    
    return (++selectedCount < 2);
}

- singleClick:sender
{
    if ([self multipleCellsSelected]) {
	[textField setStringValueNoCopy:""];
    } else {
	[textField setStringValueNoCopy:[[matrix selectedCell] stringValue]];
    }
    return self;
}

- doubleClick:sender
{
    NXRunAlertPanel(NULL, [stringTable valueForStringKey:"doubleClick"],
    		    [stringTable valueForStringKey:"clickedTwice"],
		    NULL, NULL);
    return self;
}

- displayInfoPanel:sender
{
    if (!infoPanel) {
	[NXApp loadNibSection:"InfoPanel.nib" owner:self];
    }
    [infoPanel makeKeyAndOrderFront:NULL];
    
    return self;
}

@end